package com.lottery.material.aspect;

import com.alibaba.fastjson.JSON;
import com.lottery.material.common.Constats;
import com.lottery.material.exception.ResponseException;
import com.lottery.material.utils.EmptyUtil;
import com.lottery.material.utils.MD5SignUtil;
import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
@Aspect
@Slf4j
public class CheckSignAspect {

    @Before("execution(* com.lottery.material.controller.portal.*.*.*(..))")
    public void checkSign(JoinPoint  joinPoint) {
        String errorInfo="";
        try{
            String class_name = joinPoint.getTarget().getClass().getName();
            String method_name = joinPoint.getSignature().getName();
            String[] paramNames = getFieldsName(class_name, method_name);
            Object[] method_args = joinPoint.getArgs();
            Map<String, String> map = logParam(paramNames, method_args);
            log.info(JSON.toJSONString(map));
            if (map != null) {
                String sign = map.get("sign").toUpperCase();
                String appKey=map.get("appKey");
                if(!Constats.APP_KEY.equals(appKey)){
                    log.info("appKey不正确！");
                    errorInfo="appKey不正确！";
                    throw new ResponseException(400,"appKey不正确！");
                }
                map.remove("sign");
                String realSign = MD5SignUtil.buildSign(map, Constats.APP_SECRET,"&").toUpperCase();
                if (!realSign.equals(sign)) {
                    log.info("签名错误：前台签名："+sign+";后台签名："+realSign);
                    errorInfo="签名错误！";
                    throw new ResponseException(400,"签名错误！");
                }
            }
        }catch (Exception e){
            log.error("签名错误");
            throw new ResponseException(400,"签名错误！");
        }
    }

    /**
     * 使用javassist来获取方法参数名称
     *
     * @param class_name  类名
     * @param method_name 方法名
     * @return
     * @throws Exception
     */
    private String[] getFieldsName(String class_name, String method_name) throws Exception {
        Class<?> clazz = Class.forName(class_name);
        String clazz_name = clazz.getName();
        ClassPool pool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(clazz);
        pool.insertClassPath(classPath);

        CtClass ctClass = pool.get(clazz_name);
        CtMethod ctMethod = ctClass.getDeclaredMethod(method_name);
        MethodInfo methodInfo = ctMethod.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (attr == null) {
            return null;
        }
        String[] paramsArgsName = new String[ctMethod.getParameterTypes().length];
        int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
        for (int i = 0; i < paramsArgsName.length; i++) {
            paramsArgsName[i] = attr.variableName(i + pos);
        }
        return paramsArgsName;
    }

    /**
     * 打印方法参数值  基本类型直接打印，非基本类型需要重写toString方法
     *
     * @param paramsArgsName  方法参数名数组
     * @param paramsArgsValue 方法参数值数组
     */
    private Map<String, String> logParam(String[] paramsArgsName, Object[] paramsArgsValue) {
        Map<String, String> map = new HashMap<String, String>();
        if (EmptyUtil.isEmpty(paramsArgsName) || EmptyUtil.isEmpty(paramsArgsValue)) {
            return null;
        }
//        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < paramsArgsName.length; i++) {
            //参数名
            String name = paramsArgsName[i];
            //参数值
            Object value = paramsArgsValue[i];
            //去除sign的参数
//            if ("sign".equals(name)){
//                continue;
//            }
            //去除空值
            if(EmptyUtil.isEmpty(value)){
                continue;
            }
            if (isPrimite(value.getClass())) {
                map.put(name, String.valueOf(value));
            } else {
                Map<String, String> baseBodyMap= JSON.parseObject(JSON.toJSONString(value),Map.class);
                map.putAll(baseBodyMap);
                //map.put(name, value.toString());
            }
        }
        return map;
    }

    /**
     * 判断是否为基本类型：包括String
     *
     * @param clazz clazz
     * @return true：是;     false：不是
     */
    private boolean isPrimite(Class<?> clazz) {
        if (clazz.isPrimitive() || clazz == String.class) {
            return true;
        } else {
            return false;
        }
    }

}
